package cn.anecansaitin.industrialization_expansion.common.item;

import cn.anecansaitin.industrialization_expansion.ModConstant;
import cn.anecansaitin.industrialization_expansion.api.common.cap.IModifiedAttribute;
import cn.anecansaitin.industrialization_expansion.api.common.cap.IModuleStorage;
import cn.anecansaitin.industrialization_expansion.client.item.ISTER.ISTERCallable;
import cn.anecansaitin.industrialization_expansion.client.util.InputManager;
import cn.anecansaitin.industrialization_expansion.common.CommonEventHooks;
import cn.anecansaitin.industrialization_expansion.common.TranslationText;
import cn.anecansaitin.industrialization_expansion.common.cap.CapabilityModifiedAttribute;
import cn.anecansaitin.industrialization_expansion.common.cap.CapabilityModuleStorage;
import cn.anecansaitin.industrialization_expansion.common.cap.ItemEnergyStorage;
import cn.anecansaitin.industrialization_expansion.common.cap.provider.ModifiedToolProvider;
import cn.anecansaitin.industrialization_expansion.common.entity.ModItemEntity;
import com.google.common.collect.*;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.Attribute;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.item.ToolItem;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.*;
import net.minecraft.world.World;
import net.minecraftforge.common.ToolType;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import org.lwjgl.glfw.GLFW;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Consumer;

/*
 * NBT结构
 *  nbt
 *   ├ contain_changed (list)
 *   │   ├ 0 0 (int)
 *   │   └ 1 2 (int)
 *   ├ tool_property (compound)
 *   │   └ damage (int)
 *   └ cap
 *       ├ energy
 *       │   ├ ┌──────────────┐
 *       │   ├ │   EnergyCap  │
 *       │   ├ │ serializeNBT │
 *       │   └ └──────────────┘
 *       └ items
 *           ├ ┌──────────────┐
 *           ├ │    ItemCap   │
 *           ├ │ serializeNBT │
 *           └ └──────────────┘
 * */
public class ModifiedTool extends ToolItem {
    private final Multimap<Attribute, AttributeModifier> emptyModifiers = ImmutableMultimap.of();
    private final Set<Block> pickaxeDiggables = ImmutableSet.of(Blocks.ACTIVATOR_RAIL, Blocks.COAL_ORE, Blocks.COBBLESTONE, Blocks.DETECTOR_RAIL, Blocks.DIAMOND_BLOCK, Blocks.DIAMOND_ORE, Blocks.POWERED_RAIL, Blocks.GOLD_BLOCK, Blocks.GOLD_ORE, Blocks.NETHER_GOLD_ORE, Blocks.ICE, Blocks.IRON_BLOCK, Blocks.IRON_ORE, Blocks.LAPIS_BLOCK, Blocks.LAPIS_ORE, Blocks.MOSSY_COBBLESTONE, Blocks.NETHERRACK, Blocks.PACKED_ICE, Blocks.BLUE_ICE, Blocks.RAIL, Blocks.REDSTONE_ORE, Blocks.SANDSTONE, Blocks.CHISELED_SANDSTONE, Blocks.CUT_SANDSTONE, Blocks.CHISELED_RED_SANDSTONE, Blocks.CUT_RED_SANDSTONE, Blocks.RED_SANDSTONE, Blocks.STONE, Blocks.GRANITE, Blocks.POLISHED_GRANITE, Blocks.DIORITE, Blocks.POLISHED_DIORITE, Blocks.ANDESITE, Blocks.POLISHED_ANDESITE, Blocks.STONE_SLAB, Blocks.SMOOTH_STONE_SLAB, Blocks.SANDSTONE_SLAB, Blocks.PETRIFIED_OAK_SLAB, Blocks.COBBLESTONE_SLAB, Blocks.BRICK_SLAB, Blocks.STONE_BRICK_SLAB, Blocks.NETHER_BRICK_SLAB, Blocks.QUARTZ_SLAB, Blocks.RED_SANDSTONE_SLAB, Blocks.PURPUR_SLAB, Blocks.SMOOTH_QUARTZ, Blocks.SMOOTH_RED_SANDSTONE, Blocks.SMOOTH_SANDSTONE, Blocks.SMOOTH_STONE, Blocks.STONE_BUTTON, Blocks.STONE_PRESSURE_PLATE, Blocks.POLISHED_GRANITE_SLAB, Blocks.SMOOTH_RED_SANDSTONE_SLAB, Blocks.MOSSY_STONE_BRICK_SLAB, Blocks.POLISHED_DIORITE_SLAB, Blocks.MOSSY_COBBLESTONE_SLAB, Blocks.END_STONE_BRICK_SLAB, Blocks.SMOOTH_SANDSTONE_SLAB, Blocks.SMOOTH_QUARTZ_SLAB, Blocks.GRANITE_SLAB, Blocks.ANDESITE_SLAB, Blocks.RED_NETHER_BRICK_SLAB, Blocks.POLISHED_ANDESITE_SLAB, Blocks.DIORITE_SLAB, Blocks.SHULKER_BOX, Blocks.BLACK_SHULKER_BOX, Blocks.BLUE_SHULKER_BOX, Blocks.BROWN_SHULKER_BOX, Blocks.CYAN_SHULKER_BOX, Blocks.GRAY_SHULKER_BOX, Blocks.GREEN_SHULKER_BOX, Blocks.LIGHT_BLUE_SHULKER_BOX, Blocks.LIGHT_GRAY_SHULKER_BOX, Blocks.LIME_SHULKER_BOX, Blocks.MAGENTA_SHULKER_BOX, Blocks.ORANGE_SHULKER_BOX, Blocks.PINK_SHULKER_BOX, Blocks.PURPLE_SHULKER_BOX, Blocks.RED_SHULKER_BOX, Blocks.WHITE_SHULKER_BOX, Blocks.YELLOW_SHULKER_BOX, Blocks.PISTON, Blocks.STICKY_PISTON, Blocks.PISTON_HEAD);
    private final Set<Material> axeDiggableMaterials = Sets.newHashSet(Material.WOOD, Material.NETHER_WOOD, Material.PLANT, Material.REPLACEABLE_PLANT, Material.BAMBOO, Material.VEGETABLE);
    private final Set<Block> axeOtherDiggableBlocks = Sets.newHashSet(Blocks.LADDER, Blocks.SCAFFOLDING, Blocks.OAK_BUTTON, Blocks.SPRUCE_BUTTON, Blocks.BIRCH_BUTTON, Blocks.JUNGLE_BUTTON, Blocks.DARK_OAK_BUTTON, Blocks.ACACIA_BUTTON, Blocks.CRIMSON_BUTTON, Blocks.WARPED_BUTTON);
    private final Set<Block> hoeDiggables = ImmutableSet.of(Blocks.NETHER_WART_BLOCK, Blocks.WARPED_WART_BLOCK, Blocks.HAY_BLOCK, Blocks.DRIED_KELP_BLOCK, Blocks.TARGET, Blocks.SHROOMLIGHT, Blocks.SPONGE, Blocks.WET_SPONGE, Blocks.JUNGLE_LEAVES, Blocks.OAK_LEAVES, Blocks.SPRUCE_LEAVES, Blocks.DARK_OAK_LEAVES, Blocks.ACACIA_LEAVES, Blocks.BIRCH_LEAVES);
    private final Set<Block> shovelDiggables = Sets.newHashSet(Blocks.CLAY, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL, Blocks.FARMLAND, Blocks.GRASS_BLOCK, Blocks.GRAVEL, Blocks.MYCELIUM, Blocks.SAND, Blocks.RED_SAND, Blocks.SNOW_BLOCK, Blocks.SNOW, Blocks.SOUL_SAND, Blocks.GRASS_PATH, Blocks.WHITE_CONCRETE_POWDER, Blocks.ORANGE_CONCRETE_POWDER, Blocks.MAGENTA_CONCRETE_POWDER, Blocks.LIGHT_BLUE_CONCRETE_POWDER, Blocks.YELLOW_CONCRETE_POWDER, Blocks.LIME_CONCRETE_POWDER, Blocks.PINK_CONCRETE_POWDER, Blocks.GRAY_CONCRETE_POWDER, Blocks.LIGHT_GRAY_CONCRETE_POWDER, Blocks.CYAN_CONCRETE_POWDER, Blocks.PURPLE_CONCRETE_POWDER, Blocks.BLUE_CONCRETE_POWDER, Blocks.BROWN_CONCRETE_POWDER, Blocks.GREEN_CONCRETE_POWDER, Blocks.RED_CONCRETE_POWDER, Blocks.BLACK_CONCRETE_POWDER, Blocks.SOUL_SOIL);
    protected final List<ITextComponent> toolTip = new ArrayList<>();


    public ModifiedTool() {
        super(0, 0, new EmptyTier(), new HashSet<>(), new Properties().tab(ModConstant.TABLE).setISTER(() -> new ISTERCallable()));
    }

    @Override
    public @Nonnull ActionResult<ItemStack> use(@Nonnull World world, @Nonnull PlayerEntity player, @Nonnull Hand hand) {
        return CommonEventHooks.fireToolUseEvent(world, player, hand);
    }

    @Override
    public @Nonnull ActionResultType useOn(@Nonnull ItemUseContext context) {
        return CommonEventHooks.fireToolUseOnBlockEvent(context);
    }

    @Override
    public boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, PlayerEntity player) {
        return CommonEventHooks.fireToolBreakBlockEvent(itemstack, pos, player);
    }

    @Override
    public boolean mineBlock(ItemStack pStack, World pLevel, BlockState pState, BlockPos pPos, LivingEntity pEntityLiving) {
        return super.mineBlock(pStack, pLevel, pState, pPos, pEntityLiving);
    }

    /**
     * @param stack    物品堆
     * @param amount   总共要扣除的耐久
     * @param entity   对该物品造成耐久扣除的实体
     * @param onBroken 当物品完全损坏时调用的方法
     * @param <T>      实体的类
     * @return 按照原版方式进行扣除的耐久 <br/>
     * 该方法可用于实现在耐久扣除前先进行能量扣除
     */
    @Override
    public <T extends LivingEntity> int damageItem(ItemStack stack, int amount, T entity, Consumer<T> onBroken) {
        //消耗电力
        LazyOptional<IEnergyStorage> cap = getEnergyCap(stack);

        if (!cap.isPresent())
            return amount;

        IEnergyStorage energy = cap.orElseThrow(RuntimeException::new);
        int residue = amount * getEnergyRatio(stack);
        int i = energy.extractEnergy(residue, false);

        return (int) Math.ceil((residue - i) / 50d);
    }

    /**
     * @param stack 物品堆
     * @param nbt   物品的序列化nbt
     * @return 能力提供者 <br/>
     * 这个方法会在对应的ItemStack里存放能力提供者，只要物品不消失，能力就一直存在，不用担心能力对象的频繁创建
     */
    @Nullable
    @Override
    public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundNBT nbt) {
        return new ModifiedToolProvider(stack);
    }

    /**
     * @param stack 物品堆
     * @param world 世界
     * @param list  悬浮文本列表
     * @param flag  悬浮文本类型
     */
    @Override
    public void appendHoverText(@Nonnull ItemStack stack, @Nullable World world, @Nonnull List<ITextComponent> list, @Nonnull ITooltipFlag flag) {
        if (world == null)
            return;

        FontRenderer font = Minecraft.getInstance().font;
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);

        if (InputManager.isKeyDown(GLFW.GLFW_KEY_LEFT_ALT)) {
            //经验恢复
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.xp_repair_ratio").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.format("%.2f", moduleCap.getXpRepairRatio())).withStyle(TextFormatting.AQUA)));
            //附魔能力
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.enchantability").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.valueOf(moduleCap.getEnchantability())).withStyle(TextFormatting.DARK_PURPLE)));
            //材料
            NonNullList<Ingredient> materials = moduleCap.getMaterial();

            if (!materials.isEmpty()) {
                if (InputManager.isKeyDown(GLFW.GLFW_KEY_LEFT_SHIFT)) {
                    IFormattableTextComponent toolTypeCache = new StringTextComponent(" ");
                    list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.material").withStyle(TextFormatting.GOLD).append(" [").append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".key.press", "Shift").withStyle(TextFormatting.WHITE)).append("]"));

                    for (Ingredient material : materials) {
                        //字符总长度小于120则让其在一行显示
                        if (font.width(toolTypeCache) > 120) {
                            list.add(toolTypeCache);
                            toolTypeCache = new StringTextComponent(" ");
                        }

                        toolTypeCache.append(((IFormattableTextComponent)material.getItems()[0].getDisplayName()).withStyle(TextFormatting.YELLOW)).append(" ");
                    }

                    //最后保存的不是空的则要将其加入列表
                    if (!toolTypeCache.getString().equals(" "))
                        list.add(toolTypeCache);

                } else
                    list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.material").withStyle(TextFormatting.GOLD).append(" [").append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".key.press", "Shift").withStyle(TextFormatting.GRAY)).append("]"));
            }
            //更多
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.more").withStyle(TextFormatting.GOLD).append(" [").append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".key.release", "Alt").withStyle(TextFormatting.WHITE)).append("]"));
        } else {
            //工具等级
            Map<ToolType, Integer> map = moduleCap.getToolTypeLevel();

            if (!map.isEmpty()) {
                if (InputManager.isKeyDown(GLFW.GLFW_KEY_LEFT_SHIFT)) {
                    IFormattableTextComponent toolTypeCache = new StringTextComponent(" ");
                    list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.tool_type").withStyle(TextFormatting.GOLD).append(" [").append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".key.press", "Shift").withStyle(TextFormatting.WHITE)).append("]"));

                    for (Map.Entry<ToolType, Integer> entry : map.entrySet()) {
                        //字符总长度小于120则让其在一行显示
                        if (font.width(toolTypeCache) > 120) {
                            list.add(toolTypeCache);
                            toolTypeCache = new StringTextComponent(" ");
                        }

                        TranslationTextComponent level = (TranslationTextComponent) new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.tool_type.level", entry.getValue()).withStyle(TextFormatting.YELLOW);
                        IFormattableTextComponent typeAndLevel = TranslationText.getToolType(entry.getKey()).copy().append(level);
                        toolTypeCache.append(typeAndLevel).append(" ");
                    }

                    //最后保存的不是空的则要将其加入列表
                    if (!toolTypeCache.getString().equals(" "))
                        list.add(toolTypeCache);

                } else
                    list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.tool_type").withStyle(TextFormatting.GOLD).append(" [").append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".key.press", "Shift").withStyle(TextFormatting.GRAY)).append("]"));
            }

            //能量
            LazyOptional<IEnergyStorage> lazyEnergy = getEnergyCap(stack);

            if (lazyEnergy.isPresent()) {
                IEnergyStorage energyCap = lazyEnergy.orElseThrow(RuntimeException::new);

                if (energyCap.getMaxEnergyStored() > 0) {
                    list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.energy").withStyle(TextFormatting.GRAY).append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.energy.num", energyCap.getEnergyStored(), energyCap.getMaxEnergyStored()).withStyle(TextFormatting.DARK_AQUA)));
                }
            }

            //耐久
            int maxDurability = getMaxDamage(stack);

            if (maxDurability > 0) {
                int durability = maxDurability - getDamage(stack);
                list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.durability").withStyle(TextFormatting.GRAY).append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.durability.num", durability, maxDurability).withStyle(TextFormatting.GREEN)));
            }

            //破盾
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.disabled_shield").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.valueOf(moduleCap.canDisableShield())).withStyle(TextFormatting.DARK_PURPLE)));
            //挖掘速度
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.destroy_speed").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.format("%.2f", moduleCap.getDestroySpeed())).withStyle(TextFormatting.YELLOW)));
            //火焰保护
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.fire_resistant").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.valueOf(moduleCap.isFireImmune())).withStyle(TextFormatting.RED)));
            //更多
            list.add(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".modified_tool.more").withStyle(TextFormatting.GOLD).append(" [").append(new TranslationTextComponent("text." + ModConstant.MOD_ID + ".key.press", "Alt").withStyle(TextFormatting.GRAY)).append("]"));
        }

        list.addAll(getToolTip(stack));
    }

    /**
     * @param stack      物品堆
     * @param tool       询问的工具类型
     * @param player     尝试挖掘方块的玩家
     * @param blockState 被挖掘的方块
     * @return 挖掘等级
     */
    @Override
    public int getHarvestLevel(@Nonnull ItemStack stack, @Nonnull ToolType tool, @Nullable PlayerEntity player, @Nullable BlockState blockState) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return 0;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.getHarvestLevel(tool, player, blockState);
    }

    /**
     * @param stack    物品堆
     * @param shield   被击中的盾牌
     * @param entity   持有盾牌的实体
     * @param attacker 持有物品的实体
     * @return 能否破盾
     */
    @Override
    public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return false;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.canDisableShield(shield, entity, attacker);
    }

    /**
     * @param stack 物品堆
     * @return 是否展示耐久条
     */
    @Override
    public boolean showDurabilityBar(ItemStack stack) {
        LazyOptional<IEnergyStorage> energyCap = getEnergyCap(stack);

        if (energyCap.isPresent()) {
            IEnergyStorage energy = energyCap.orElseThrow(RuntimeException::new);
            int maxEnergyStored = energy.getMaxEnergyStored();

            if (maxEnergyStored > 0 && energy.getEnergyStored() < maxEnergyStored && energy.getEnergyStored() > 0)
                return true;
        }

        return super.showDurabilityBar(stack);
    }

    /**
     * @param stack 物品堆
     * @return 耐久条的长度
     */
    @Override
    public double getDurabilityForDisplay(ItemStack stack) {
        LazyOptional<IEnergyStorage> energyCap = getEnergyCap(stack);

        if (energyCap.isPresent()) {
            IEnergyStorage energy = energyCap.orElseThrow(RuntimeException::new);
            int stored = energy.getEnergyStored();
            int max = energy.getMaxEnergyStored();

            if (stored > 0 && stored < max)
                return 1 - ((double) stored) / max;
        }

        return super.getDurabilityForDisplay(stack);
    }

    /**
     * @param stack 物品堆
     * @return 耐久条的颜色
     */
    @Override
    public int getRGBDurabilityForDisplay(ItemStack stack) {
        LazyOptional<IEnergyStorage> energyCap = getEnergyCap(stack);
        if (energyCap.isPresent()) {
            IEnergyStorage energy = energyCap.orElseThrow(RuntimeException::new);

            if (energy.getEnergyStored() > 0)
                return 0x10FAF1;
        }

        int maxDurability = getMaxDamage(stack);
        int damage = getDamage(stack);

        if (maxDurability > 0 && damage > 0)
            return super.getRGBDurabilityForDisplay(stack);

        return 0x000000;
    }

    /**
     * @param stack 物品堆
     * @param book  附魔书
     * @return 是否允许指定附魔书附魔
     */
    @Override
    public boolean isBookEnchantable(ItemStack stack, ItemStack book) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return false;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.isEnchantable(EnchantmentHelper.getEnchantments(book).keySet());
    }

    /**
     * @param stack 物品堆
     * @return 物品附魔能力
     */
    @Override
    public int getItemEnchantability(ItemStack stack) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return 0;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.getEnchantability();
    }

    @Override
    public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return false;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.isEnchantable(enchantment);
    }

    /**
     * @param stack 物品堆
     * @return 是否有自定义的物品掉落物实体
     */
    @Override
    public boolean hasCustomEntity(ItemStack stack) {
        return true;
    }

    /**
     * @param world    将要生成的世界
     * @param location 已经生成的物品掉落物实体
     * @param stack    物品堆
     * @return 自定义的物品实体
     */
    @Nullable
    @Override
    public Entity createEntity(World world, Entity location, ItemStack stack) {
        ItemEntity itemEntity = (ItemEntity) location;
        ModItemEntity entity = new ModItemEntity(world, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack);
        entity.setPickUpDelay(40);
        entity.setThrower(itemEntity.getThrower());
        Vector3d movement = itemEntity.getDeltaMovement();
        entity.setDeltaMovement(movement.x(), movement.y(), movement.z());
        return entity;
    }

    /**
     * @param stack 物品堆
     * @return 是否有合成返还物品
     */
    @Override
    public boolean hasContainerItem(ItemStack stack) {
        return true;
    }

    /**
     * @param stack 物品堆
     * @return 物品合成后的返回物品
     * 例如：牛奶桶合成蛋糕返还桶
     */
    @Override
    public ItemStack getContainerItem(ItemStack stack) {
        stack.getItem().damageItem(stack, 1, null, e -> {
        });

        if (stack.getDamageValue() == stack.getMaxDamage())
            return ItemStack.EMPTY;

        return stack;
    }

    /**
     * @param stack 物品堆
     * @return 每一点经验能修复的耐久度
     */
    @Override
    public float getXpRepairRatio(ItemStack stack) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return 2f;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.getXpRepairRatio();
    }

    /**
     * @param stack 物品堆
     * @param state 尝试被挖掘的方块
     * @return 方块是否能被正确的挖掘
     */
    @Override
    public boolean canHarvestBlock(ItemStack stack, BlockState state) {
        Set<ToolType> toolTypes = getToolTypes(stack);

        for (ToolType toolType : toolTypes) {
            if (state.getHarvestTool() == toolType)
                return true;

            switch (toolType.getName()) {
                case "pickaxe":
                    if (pickaxeDiggables.contains(state.getBlock()))
                        return true;
                    break;
                case "axe":
                    if (axeOtherDiggableBlocks.contains(state.getBlock()))
                        return true;
                    else if (axeDiggableMaterials.contains(state.getMaterial()))
                        return true;
                    break;
                case "hoe":
                    if (hoeDiggables.contains(state.getBlock()))
                        return true;
                    break;
                case "shovel":
                    if (shovelDiggables.contains(state.getBlock()))
                        return true;
                    break;
            }
        }

        return false;
    }

    /**
     * @param stack 物品堆
     * @return 物品对应的工具类型
     */
    @Override
    public @Nonnull Set<ToolType> getToolTypes(@Nonnull ItemStack stack) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return new HashSet<>();

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.getToolTypes();
    }

    /**
     * @param stack 物品堆
     * @return 物品的名字
     * 通过头、把手、配重来定义物品名称
     */
    @Override
    public @Nonnull ITextComponent getName(@Nonnull ItemStack stack) {
        return getToolName(stack);
    }

    /**
     * @return 工具的伤害
     * 原版只用于怪物交换手中的武器
     */
    @Override
    public float getAttackDamage() {
        return 0;
    }

    /**
     * @param type  物品所装备的格子
     * @param stack 物品堆
     * @return 物品对应的属性以及其操作符
     */
    @Override
    public Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlotType type, ItemStack stack) {
        if (type == EquipmentSlotType.MAINHAND) {
            LazyOptional<IModifiedAttribute> lazyAttribute = getAttributeCap(stack);

            if (!lazyAttribute.isPresent())
                return emptyModifiers;

            IModifiedAttribute attributeCap = lazyAttribute.orElseThrow(RuntimeException::new);
            return attributeCap.getAttribute();
        } else
            return emptyModifiers;
    }

    /**
     * @param stack 物品堆
     * @param state 被挖掘的方块信息
     * @return 挖掘方块的速度
     */
    @Override
    public float getDestroySpeed(@Nonnull ItemStack stack, @Nonnull BlockState state) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent()) {
            return 1f;
        }

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.getDestroySpeed(state);
    }

    /**
     * @param toRepair 被修复的物品
     * @param repair   用于修复的物品
     * @return 物品是否能被指定物品修复<br />
     * 三次使用头的材料，一次把手的材料，一次配重的材料，循环
     */
    @Override
    public boolean isValidRepairItem(@Nonnull ItemStack toRepair, @Nonnull ItemStack repair) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(toRepair);

        if (!lazyModule.isPresent())
            return false;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.isValidRepairItem(repair);
    }

    /**
     * @param stack 物品堆
     * @return 物品是否有耐久 <br/>
     * 因为这个方法会在物品创建时调用。当调用ItemStack.copy()时，会先new ItemStack，此时物品的nbt还未传递，为了避免生成不正确的能力，此处默认返回true。
     */
    @Override
    public boolean isDamageable(ItemStack stack) {
        return true;
    }

    /**
     * @param stack 物品堆
     * @return 物品的最高耐久<br />
     * 从物品存储能力中获取所有组件的耐久设定并加总返回
     */
    @Override
    public int getMaxDamage(ItemStack stack) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return 0;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.getMaxDurability();
    }

    /**
     * @param stack 物品堆
     * @return 物品的耐久值
     */
    @Override
    public int getDamage(ItemStack stack) {
        CompoundNBT property = getProperty(stack);

        if (property.contains("damage"))
            return property.getInt("damage");

        return 0;
    }

    /**
     * @param stack  物品堆
     * @param damage 新的被损坏的耐久值
     */
    @Override
    public void setDamage(ItemStack stack, int damage) {
        CompoundNBT property = getProperty(stack);
        property.putInt("damage", Math.max(0, damage));
    }

    /**
     * @param stack 物品堆
     * @return 耐久是否不满
     */
    @Override
    public boolean isDamaged(ItemStack stack) {
        int damage = getDamage(stack);
        return damage > 0;
    }

    public boolean isFireImmune(ItemStack stack) {
        LazyOptional<IModuleStorage> lazyModule = getModuleCap(stack);

        if (!lazyModule.isPresent())
            return false;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);
        return moduleCap.isFireImmune();
    }

    /**
     * @param stack 物品堆
     * @return 获取物品的属性NBT
     */
    private CompoundNBT getProperty(ItemStack stack) {
        return stack.getOrCreateTagElement("tool_property");
    }

    /**
     * @param tool 复合工具
     * @return 组合成功返回工具，否则返回空（ItemStack.EMPTY）<br/>
     * 用来为工具初次设置属性
     */
    public ItemStack assembleTool(ItemStack tool, IntArrayList coreFlg, NonNullList<ItemStack> modules, int size) {
        tool = tool.copy();
        Item item = tool.getItem();

        if (!(item instanceof ModifiedTool))
            return ItemStack.EMPTY;

        LazyOptional<IModuleStorage> lazyModule = getModuleCap(tool);

        if (!lazyModule.isPresent())
            return ItemStack.EMPTY;

        IModuleStorage moduleCap = lazyModule.orElseThrow(RuntimeException::new);

        if (!moduleCap.format(coreFlg, modules, size))
            return ItemStack.EMPTY;

        LazyOptional<IEnergyStorage> lazyEnergy = getEnergyCap(tool);

        if (!lazyEnergy.isPresent())
            return ItemStack.EMPTY;

        ItemEnergyStorage energyCap = (ItemEnergyStorage) lazyEnergy.orElseThrow(RuntimeException::new);
        //初始化属性
        int capacity = moduleCap.getMaxEnergyCapacity();
        double damage = moduleCap.getDamage();
        double speed = moduleCap.getAttackSpeed();

        energyCap.format(capacity, 100, 100, 0);
        CompoundNBT property = getProperty(tool);
        //初始化耐久
        property.putInt("damage", 0);
        //属性表
        LazyOptional<IModifiedAttribute> lazyAttribute = getAttributeCap(tool);

        if (!lazyAttribute.isPresent())
            return ItemStack.EMPTY;

        IModifiedAttribute attributeCap = lazyAttribute.orElseThrow(RuntimeException::new);
        ArrayListMultimap<Attribute, AttributeModifier> multiMap = ArrayListMultimap.create();
        multiMap.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Tool modifier", damage, AttributeModifier.Operation.ADDITION));
        //玩家的默认初始攻速为4，为防止完全无法使用武器，攻速最低为-3.8
        multiMap.put(Attributes.ATTACK_SPEED, new AttributeModifier(BASE_ATTACK_SPEED_UUID, "Tool modifier", Math.max(speed, -3.8), AttributeModifier.Operation.ADDITION));
        attributeCap.setAttribute(multiMap);
        return tool;
    }

    /**
     * @param stack 物品堆
     * @return 工具对应的名字 <br/>
     * 该返回值影响物品拿在手中时显示的名字，如镐、锄、螺丝刀
     */
    public TranslationTextComponent getToolName(ItemStack stack) {
        return TranslationText.MODIFIED;
    }

    public int getEnergyRatio(ItemStack stack) {
        return 50;
    }

    public List<ITextComponent> getToolTip(ItemStack stack) {
        return toolTip;
    }

    public String getDefaultIcon(ItemStack stack) {
        return "item_handle";
    }

    /**
     * @param stack 物品堆
     * @return 物品内的能量存储能力
     */
    private LazyOptional<IEnergyStorage> getEnergyCap(ItemStack stack) {
        return stack.getCapability(CapabilityEnergy.ENERGY);
    }

    /**
     * @param stack 物品堆
     * @return 物品内的配件存储能力
     */
    private LazyOptional<IModuleStorage> getModuleCap(ItemStack stack) {
        return stack.getCapability(CapabilityModuleStorage.MODULE_STORAGE);
    }

    /**
     * @param stack 物品堆
     * @return 物品内的可变属性能力
     */
    private LazyOptional<IModifiedAttribute> getAttributeCap(ItemStack stack) {
        return stack.getCapability(CapabilityModifiedAttribute.ATTRIBUTE);
    }
}
